C#中对Oracle中Clob类型处理解析 |
您所在的位置:网站首页 › oracle 解析clob里的xml › C#中对Oracle中Clob类型处理解析 |
无 解决办法: 无
方式3:采用参数形式,但是参数类型写为OracleType. NVarChar 代码: string id = Guid.NewGuid().ToString(); OracleCommand cmd = Conn.CreateCommand(); cmd.CommandText = "insert into xx(id,test) values('" + id + "',:p1)"; OracleParameter p1 = new OracleParameter("p1", OracleType. NVarChar); p1.Value = data; // data是一个变量,存储你要插入的字符串 cmd.Parameters.Add(p1); cmd.ExecuteNonQuery();情况分析: 为什么要写这种方式,因为这种方式和采用NHibernate的方式很相似,先看看在这种方式会产生什么情况。 当data的字节数在0- 2000 之间时正常插入,大于4000时也正常插入,但在 2000 -4000时则失败,报错(ORA-01461:仅可以插入LONG列的LONG值赋值) 原因分析: 没有采用对应的Oracle类型。 解决办法: 采用OracleType.Clob
下边采用NHibernate插入数据,NHibernate具体怎用不在本次讨论范围。 NHibernate采用的版本为 1.2.1 .4000。 下边大至把简要配置写下。
App.config
xx.cs using System; using System.Collections.Generic; using System.Text; namespace Test.Enties { [Serializable] public class Xx { public Xx() { } private string id; public virtual string Id { get { return id; } set { id = value; } } public virtual string Test { get { return test; } set { test = value; } } private string test; } }xx.hbm.xml
说明: 这里的驱动用的NHibernate.Driver.OracleClientDriver,其实是对微软的OracleClient的封装啦,其实内部还是调用微软的OracleClient的东东。引用System.Data.OracleClient.dll即可OracleClient。
做好上边的配置后,便有了以下的方式 方式4:采用NHibernate 代码: string id = Guid.NewGuid().ToString(); Xx xx = new Xx(); xx.Test = data; // data是一个变量,存储你要插入的字符串 xx.Id = id; ISession session = SessionFactory.OpenSession(); session.Save(xx); session.Flush();情况分析: 当data的字节数在0- 2000 之间时正常插入,大于4000时也正常插入,但在 2000 -4000时则失败,报错(ORA-01461:仅可以插入LONG列的LONG值赋值).情况和方式3的情况一样。 原因分析: NHibernate在用OracleClient映射StringClob时,设置参数类型为OracleType. NVarChar,导致插入有BUG。网上有人推测是OracleClient的BUG所致,理由是换用OracleDataAccess即可解决。
为什么说NHibernate将参数类型设置为OracleType.NVarChar呢?看下边
找到NHibernate的源代码,把它加入你的工程。记得不要移动NHibernate位置直接加入工程,直接在NHibernate的安装目录引用进来。
2. 在 Test 解决方案中添加NHibernate的项目引用。 经过上边两个步骤我们就可以跟踪调试NHibernate了 跟踪代码session.Save(xx);看看它究竟做了啥。 当我们跟进CommandSetBatchingBatcher时,可以得到以下信息(如图中的调试信息)。CurrentBatch类型是OracleClientCommandSet,OracleClientCommandSet看源码得知是对微软的OracleCommandSet的封装,因为这个类internal sealed class,所以我们的程序里是找不到这个类的,不过NHibernate通过反射使用了它的功能。OracleCommandSet可能用作批处理的,就是一次处理多个SQL语句的,不是太了解,谁知道请指教。
CommandSetBatchingBatcher的源码 internal class OracleClientCommandSet : DbCommandSet { private static System.Type oracleCmdSetType; static OracleClientCommandSet() { Assembly sysDataOracleClient = Assembly.Load("System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); oracleCmdSetType = sysDataOracleClient.GetType("System.Data.OracleClient.OracleCommandSet"); Debug.Assert(oracleCmdSetType != null, "Could not find OracleCommandSet!"); } protected override object CreateInternalCommandSet() { return Activator.CreateInstance(oracleCmdSetType, true); } }跟踪CurrentBatch可以看到 CommandText: declare type refcursortype is ref cursor; begin INSERT INTO z3 ( test , id) VALUES (:p2, :p3); :r1_4 := sql%rowcount; end;
这里的p2就是我们的Clob类型字段的参数啦。 再看p2的OracleType是NVarChar,是不是有点明白啦,对了, 跟我们3一样,参数类型错掉了。
解决办法: 使用NHibernate的自定义类型,不是太会,幸好网上有高人提供代码,在此想高人致谢。这样我们通过自定义类型来设置正确的OracleType即可。在项目中添加两个类。 PatchForOracleLobField.cs using System; using System.Collections.Generic; using System.Data; using System.Text; using NHibernate; using NHibernate.SqlTypes; using NHibernate.UserTypes; namespace Test.type { public abstract class PatchForOracleLobField : IUserType { public PatchForOracleLobField() { } public bool IsMutable { get { return true; } } public System.Type ReturnedType { get { return typeof(String); } } public SqlType[] SqlTypes { get { return new SqlType[] { NHibernateUtil.String.SqlType }; } } public object DeepCopy(object value) { return value; } public new bool Equals(object x, object y) { return x == y; } public int GetHashCode(object x) { return x.GetHashCode(); } public object Assemble(object cached, object owner) { return DeepCopy(cached); } public object Disassemble(object value) { return DeepCopy(value); } public object NullSafeGet(IDataReader rs, string[] names, object owner) { return NHibernate.NHibernateUtil.StringClob.NullSafeGet(rs, names[0]); } public abstract void NullSafeSet(IDbCommand cmd, object value, int index); public object Replace(object original, object target, object owner) { return original; } } }
OracleClobField.cs using System; using System.Collections.Generic; using System.Data; using System.Data.OracleClient; using System.Text; namespace Test.type { public class OracleClobField : PatchForOracleLobField { public override void NullSafeSet(IDbCommand cmd, object value, int index) { if (cmd is OracleCommand) { //CLob、NClob类型的字段,存入中文时参数的OracleDbType必须设置为OracleDbType.Clob //否则会变成乱码(Oracle 10g client环境) OracleParameter param = cmd.Parameters[index] as OracleParameter; if (param != null) { param.OracleType = OracleType.Clob;// 关键就这里啦 param.IsNullable = true; } } NHibernate.NHibernateUtil.StringClob.NullSafeSet(cmd, value, index); } } }
然后在映射文件中修改类型即可。 Com.Dic.Icqs.Entities.Type.OracleClobField,Com.Dic.Icqs.Entities 修改前:
修改后:
Test .type.OracleClobField是类的完整名, Test 即OracleClobField所在的程序集。 |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |